﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using formworks;
using System.Data;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using formworks.old;

namespace codefactory
{
    /// <summary>
    /// 代码生成引擎
    /// </summary>
    public class CodeEngine
    {
        public DB db;
        public XmlDataDocument xdoc;
        public XslCompiledTransform xslt;
        public XmlAttribute _table;
        public XmlAttribute _name;
        public FileEntity[] fileEntitys;

        
        /************************************************************************/
        /* 
SQL Server 2000	C#	CodeSmith
数据类型	取值范围	数据类型	取值范围	空值代替值	数据类型
bigint	-2^63 (-9,223,372,036,854,775,807) 至 2^63-1 (9,223,372,036,854,775,807)	Int64	-9,223,372,036,854,775,808；即十六进制的 0x8000000000000000至9,223,372,036,854,775,807；即十六进制的 0x7FFFFFFFFFFFFFFF	Int64.MinValue	Int64
binary	固定长度的 n 个字节二进制数据。N 必须从 1 到 8,000。存储空间大小为 n+4 字节。	Byte[]		null	Binary
bit	True，False	enum	0，1，-1（使用一个枚举变量来代替） public enum bitNull    {     False,     True,     Null = -1 };	-1	Boolean
char	长度为 n 个字节的固定长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大小为 n 个字节。	string		null	AnsiStringFixedLength
datetime	存储从 1753 年 1 月 1 日至 9999 年 12 月 31 日的日期（每个数值要求 8 个字节的存储空间）	DateTime	0001 年 1 月 1 日 00:00:00 .0000000至9999 年 12 月 31 日 23:59:59.9999999	1753-01-01 0:00:00	DateTime
decimal	从 - 10^38 +1 到 10^38 - 1	Decimal	-79,228,162,514,264,337,593,543,950,335至79,228,162,514,264,337,593,543,950,335	Decimal.MinValue	Decimal
float	从 - 1.79E + 308 到 1.79E + 308 之间的浮点数字数据	Double	-1.79769313486232e308至+1.79769313486232e308	Double.MinValue	Double
image	可变长度二进制数据介于 0 与 231-1 (2,147,483,647) 字节之间。	Byte[]		null	Binary
int	从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据（所有数字）	int	-2,147,483,648 到 2,147,483,647	-2147483648	Int32
money	货币数据值介于 -2^63 (-922,337,203,685,477.5808) 与 2^63 - 1 (+922,337,203,685,477.5807) 之间，精确到货币单位的千分之十。存储大小为 8 个字节。	Single	-3.402823e38至+3.402823e38	Single.MinValue	Currency
nchar	至多为 4000 个 Unicode 字符	string		null	StringFixedLength
ntext	可变长度 Unicode 数据的最大长度为 230- 1 (1,073,741,823) 个字符。存储大小是所输入字符个数的两倍（以字节为单位）。	string		null	String
numeric	使用最大精度时，有效值从 - 10^38 +1 到 10^38 – 1	Decimal	-79,228,162,514,264,337,593,543,950,335至79,228,162,514,264,337,593,543,950,335	Decimal.MinValue	Decimal
nvarchar	包含 n 个字符的可变长度 Unicode 字符数据。n 的值必须介于 1 与 4,000 之间。	string		null	String
real	从 ?3.40E + 38 到 3.40E + 38 之间的浮点数字数据。存储大小为 4 字节。	Single	-3.402823e38至+3.402823e38	Single.MinValue	Single
smalldatetime	从 1900 年 1 月 1 日至 2079 年 6 月 6 日的日期（每个数值要求 4 个字节的存储空间）。	DateTime	0001 年 1 月 1 日 00:00:00 .0000000至9999 年 12 月 31 日 23:59:59.9999999	1900-01-01 0:00:00	DateTime
smallint	从 -2^15 (-32,768) 到 2^15 - 1 (32,767) 的整型数据。存储大小为 2 个字节。	Int16	-32768至32767	Int16.MinValue	Int16
smallmoney	货币数据值介于 -214,748.3648 与 +214.748,3647 之间，精确到货币单位的千分之十。存储大小为 4 个字节。	Single	-3.402823e38至+3.402823e38	Single.MinValue	Currency
sql_variant	在SQL Server 2000中不支持大数据类型text, ntext, image, timestamp，其他类型均支持	Object		null	Object
text	服务器代码页中的可变长度非 Unicode 数据的最大长度为 231-1 (2,147,483,647) 个字符。当服务器代码页使用双字节字符时，存储量仍是 2,147,483,647 字节。存储大小可能小于 2,147,483,647 字节（取决于字符串）。	string		null	AnsiString
timestamp	timestamp 这种数据类型表现自动生成的二进制数，确保这些数在数据库中是唯一的。timestamp 一般用作给表行加版本戳的机制。存储大小为 8 字节。	Byte[]		null	Binary
tinyint	从 0 到 255 的整型数据。存储大小为 1 字节。	Byte	0至255	Byte.MinValue	Byte
uniqueidentifier	存储 16 字节的二进制值，该值的使用与全局唯一标识符 (GUID) 一样。GUID 是一个唯一的二进制数字；世界上的任何两台计算机都不会生成重复的 GUID 值。GUID 主要用于在拥有多个节点、多台计算机的网络中，分配必须具有唯一性的标识符。	Guid		Guid.Empty	Guid
varbinary	n 个字节变长二进制数据。n 必须从 1 到 8,000。存储空间大小为实际输入数据长度 +4 个字节，而不是 n 个字节。输入的数据长度可能为 0 字节。	Byte[]		null	Binary
varchar	长度为 n 个字节的可变长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大小为输入数据的字节的实际长度，而不是 n 个字节。所输入的数据字符长度可以为零。	string                                                                     
         */
        /************************************************************************/
        /// <summary>
        /// SQL数据类型到CSharp的数据类型
        /// 
        /// </summary>
        public List<string[]> DataTypeMapping = new List<string[]>()
        {            
            new string[]{"bigint","Int64"},
            new string[]{"binary","Byte[]"},
            new string[]{"bit","Boolean"},
            new string[]{"char","string"},
            new string[]{"datetime","DateTime"},
            new string[]{"decimal","Decimal"},
            new string[]{"float","Double"},
            new string[]{"image","Byte[]"},
            new string[]{"int","int"},
            new string[]{"money","Single"},
            new string[]{"nchar","string"},
            new string[]{"ntext","string"},
            new string[]{"numeric","Decimal"},
            new string[]{"nvarchar","string"},
            new string[]{"real","Single"},
            new string[]{"smalldatetime","DateTime"},
            new string[]{"smallint","Int16"},
            new string[]{"smallmoney","Single"},
            new string[]{"sql_variant","Object"},
            new string[]{"text","string"},
            new string[]{"timestamp","Byte[]"},
            new string[]{"tinyint","Byte"},
            new string[]{"uniqueidentifier","Guid"},
            new string[]{"varbinary","Byte[]"},
            new string[]{"varchar","string"},
            new string[]{"xml","string"}
        };        

        /// <summary>
        /// 导出文件类型
        /// </summary>
        //public enum FileType
        //{
        //    cs,
        //    html
        //}

        //public enum FileClass
        //{
        //    Entity,
        //    Implement,
        //    Interface,
        //    Html
        //}

        public string[] fileClass = new string[]
        {
            "{0}.cs",
            @"template\entity.xsl",
            "{0}Action.cs",
            @"template\implement.xsl",
            "I{0}Action.cs",
            @"template\interface.xsl",
            "{0}.html",
            @"template\html.xsl"
        };

        //public struct FileClass 
        //{
        //    public string nameFormat;
        //    public string xslPath;
        //    public FileClass(string nameFormat, string xslPath)
        //    {
        //        this.nameFormat = nameFormat;
        //        this.xslPath = xslPath;
        //    }
        //}

        public struct FileEntity
        {
            public string fileName;
            public MemoryStream memoryStream;
            //public string xsltPath;
            //public FileEntity(string fileName, MemoryStream memoryStream)
            //{
            //    this.fileName = fileName;
            //    this.memoryStream = memoryStream;
            //}

        }


        /// <summary>
        /// 代码生成引擎
        /// </summary>
        /// <param name="dtTable">表名的DataTable</param>
        public CodeEngine()
        {
            string cstr = "server=.\\SQLEXPRESS;uid=root;pwd=123;database=ComYeeMS";
            db = new DB(cstr);
            //db.getConstraints("TB_ProductOutStock");
            //List<string[]> item = new List<string[]>();
            
            
        }

        /// <summary>
        /// 表名和表描述
        /// </summary>
        /// <param name="table"></param>
        /// <param name="name"></param>
        public XmlDataDocument getXML(DataSet tableDetail, string table, string name)
        {
            DataSet ds = tableDetail.Copy();
            xdoc = new XmlDataDocument(ds);
            ds.EnforceConstraints = false; //设置DataSet不验证数据
            //
            _table = xdoc.CreateAttribute("table");
            _table.Value = table;
            _name = xdoc.CreateAttribute("name");
            _name.Value = name;
            //
            xdoc.DocumentElement.Attributes.Append(_table);
            xdoc.DocumentElement.Attributes.Append(_name);
            //
            return xdoc;
        }

        /// <summary>
        /// 合并字段和字段的主键外键关系
        /// </summary>
        /// <param name="dtField">字段表</param>
        /// <param name="dtKeys">主外键表</param>
        /// <returns></returns>
        public void merageFieldsAndKeys(DataTable dtField, DataTable dtKeys)
        {
            //DataSet ds = new DataSet();

//            DataTable dtField = dtField;
            dtField.Columns.Add("constraint_type");
            dtField.Columns.Add("constraint_name");
            dtField.Columns.Add("constraint_keys");
            dtField.Columns.Add("constraint_ref");
            dtField.Columns.Add("constraint_type_code");
            dtField.Columns.Add("constraint_ref_entity");
            dtField.Columns.Add("constraint_ref_id");

            string temp;
            string[] refCol;
            DataRow[] dr;
            for (int iter = 0; iter < dtKeys.Rows.Count; iter++)
            {
                dr = dtField.Select("name='" + dtKeys.Rows[iter]["constraint_keys"] + "'");
                if (dr.Length < 1)
                    continue;

                dr[0]["constraint_type"] = dtKeys.Rows[iter]["constraint_type"];
                dr[0]["constraint_name"] = dtKeys.Rows[iter]["constraint_name"];
                dr[0]["constraint_keys"] = dtKeys.Rows[iter]["constraint_keys"];

                temp = dr[0]["constraint_type"].ToString().Split(' ')[0];
                if (temp == "FOREIGN")
                {
                    dr[0]["constraint_ref"] = dtKeys.Rows[iter + 1]["constraint_keys"];
                    dr[0]["constraint_type_code"] = "Constraints.Types.ForeignKey";
                    //
                    refCol = dr[0]["constraint_ref"].ToString().Split(' ');
                    dr[0]["constraint_ref_entity"] = refCol[1].Split('.')[2];
                    //
                    temp = refCol[2].Replace("(", "");
                    temp = temp.Replace(")", "");
                    dr[0]["constraint_ref_id"] = temp;

                }
                else if (temp == "PRIMARY")
                {
                    dr[0]["constraint_type_code"] = "Constraints.Types.PrimaryKey";
                }

                //
                //dtOut.Rows[iter]["constraint_ref"] = dr[0]["description"];
            }

            //return dtOut;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="dtField"></param>
        public void addCSharpDataType(DataTable dtField)
        {
            dtField.Columns.Add("csharpDataType");

            for (int iter = 0; iter < dtField.Rows.Count; iter++)
            {
                dtField.Rows[iter]["csharpDataType"] = 
                    getCSharpType(dtField.Rows[iter]["dataType"].ToString());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sqlDataType"></param>
        /// <returns></returns>
        public string getCSharpType(string sqlDataType)
        {
            foreach (string[] item in DataTypeMapping)
            {
                if (item[0] == sqlDataType)
                    return item[1];
            }
            return "string";
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public FileEntity[] makeFile(string name, XmlDataDocument xmlDoc)
        {
            xslt = new XslCompiledTransform();
            
//            MemoryStream ms = new MemoryStream();
            //xslt.Transform(xmlDoc, null, ms);   //转换

            fileEntitys = new FileEntity[fileClass.Length / 2];
            int count = 0;
            //
            for (int iter = 0; iter < fileClass.Length; iter++)
            {
                
                //file name
                fileEntitys[count].fileName = 
                    string.Format(fileClass[iter], name);
                //转换xml + xsl 到 file string
                fileEntitys[count].memoryStream = new MemoryStream();
                xslt.Load(fileClass[iter+1]);   //加载样式表
                xslt.Transform(xmlDoc, null, fileEntitys[count].memoryStream);
                fileEntitys[count].memoryStream.Position = 0;
                //path = next array
                //fileEntitys[iter].xsltPath = fileClass[++iter];
                ++iter;
                count++;
                
            }//

            return fileEntitys;
        }//


        public void saveFile(string[] path)
        {
            string fileName;
            //string[] fileName = string.Format( fileClass[iter], name );
            //遍历tables列表中表的名称开始导出文件
            for (int iter = 0; iter < fileClass.Length; iter++)
            {
                //
                //fileName = string.Format(fileClass[iter], name);
                //


            }//
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string makeEntity(DataSet ds)
        {
            //
            return "";
        }

        public string makeEntityImplement()
        {
            return "";
        }

        public string makeEntityInterface()
        {
            return "";
        }

        public string makeHtml()
        {
            return "";
        }

        //public MemoryStream preser(DataSet ds)
        //{
        //    XmlDataDocument xmlDoc = new XmlDataDocument(ds);
        //    DataTable dt = ds.Tables[0];
        //    int sumQuantity = 0;
        //    for (int i = 0; i < dt.Rows.Count; i++)
        //    {
        //        sumQuantity += Convert.ToInt32(dt.Rows[i]["quantity"]);
        //    }


        //    ////总数量
        //    //ds.EnforceConstraints = false; //设置DataSet不验证数据
        //    //XmlElement xe = xmlDoc.CreateElement("SumQuantity");
        //    //xe.InnerText = sumQuantity.ToString();
        //    //xmlDoc.DocumentElement.AppendChild(xe);
        //    ////时间
        //    //xe = xmlDoc.CreateElement("DateTime");
        //    //xe.InnerText = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
        //    //xmlDoc.DocumentElement.AppendChild(xe);
        //    ////流水号
        //    //xe = xmlDoc.CreateElement("SN");
        //    //xe.InnerText = sn;
        //    //xmlDoc.DocumentElement.AppendChild(xe);

        //    //float saveCash = sourcePrice - float.Parse(xmlDoc.GetElementsByTagName("payment").Item(0).InnerText);
        //    ////节省价钱
        //    //xe = xmlDoc.CreateElement("SaveCash");
        //    //xe.InnerText = saveCash.ToString("0.0");
        //    //xmlDoc.DocumentElement.AppendChild(xe);

        //    //XslCompiledTransform xslt = new XslCompiledTransform();
        //    //xslt.Load(cfg.getPrintTypeFile(BaseFunction.Configure.PrintType.RetailList));   //加载样式表
        //    MemoryStream ms = new MemoryStream();
        //    xslt.Transform(xmlDoc, null, ms);   //转换
        //    ms.Position = 0;
        //    //wb_printRetailList.DocumentStream = ms;
        //    return ms;
        //}



    }//end class
}//end namespace
